package espacokidsadm.modelo.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;

import espacokidsadm.listener.AuditoriaListener;
import espacokidsadm.modelo.type.OndeAguardarAoTerminoAula;
import espacokidsadm.modelo.type.TipoResponsabilidade;

@Entity
@EntityListeners(AuditoriaListener.class)
public class Aluno implements Serializable, Auditavel{

	private static final long serialVersionUID = -1810353804237610715L;

	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="ID_ALUNO")
	private Integer id;
	
	@OneToOne(mappedBy="aluno", cascade=CascadeType.ALL)
	private Matricula matricula;
	
	@OneToOne(targetEntity=Pessoa.class, cascade=CascadeType.ALL)
	@JoinColumn(name="ID_PESSOA")
	private Pessoa Pessoa;
	
	@Column(name="PAIS_SEPARADOS")
	private boolean paisSeparados = false;
	
	@OneToOne(mappedBy="aluno", cascade=CascadeType.ALL)
	private SaudeAluno saudeAluno;
	
	@Enumerated(EnumType.STRING)
	@Column(name="ONDE_AGUARDAR_TERMINO_AULA")
	private OndeAguardarAoTerminoAula ondeAguardarAoTerminoAula = OndeAguardarAoTerminoAula.DENTRO_ESCOLA;
	
	private String obs;
	
	@ManyToOne
	@JoinColumn(name="ID_TURMA")
	private Turma turma;
	
	
	@ManyToMany(cascade = CascadeType.ALL)
	@JoinTable(name="RESPONSAVEL_ALUNO",
			joinColumns={
				@JoinColumn(name="ID_ALUNO")
			},
			inverseJoinColumns = {
				@JoinColumn(name="ID_RESPONSAVEL", referencedColumnName="ID_RESPONSAVEL"),
				@JoinColumn(name="TIPO_RESPONSABILIDADE", referencedColumnName="TIPO_RESPONSABILIDADE")
			}
	)
	private List<Responsavel> responsaveisAluno = new ArrayList<>();
	
	@Embedded
	private Auditoria auditoria;


	public void adicionarResponsavel(Responsavel responsavel){
		
		removerResponsavelComEsteCpf(responsavel.getId().getPessoa().getCpf());
		responsavel.getAlunos().add(this);
		getResponsaveisAluno().add(responsavel);
		
	}
	
	public void removerResponsavelComEsteCpf(String cpf){
		
		if(isExisteResponsavelNaListaComEsteCpf(cpf)){
			Responsavel responsavelDaListaQueDeveSerRemovido = obterResponsavelDaListaComEsteCpf(cpf);
			getResponsaveisAluno().remove(responsavelDaListaQueDeveSerRemovido);
		}
		
	}
	
	private Responsavel obterResponsavelDaListaComEsteCpf(String cpf){
		
		Responsavel responsavelLocalizado = null;
		
		Iterator<Responsavel> itr = getResponsaveisAluno().iterator();
		while(itr.hasNext()){
			Responsavel responsavelDaLista = itr.next();
			if(responsavelDaLista.getId().getPessoa().getCpf().equals(cpf)){
				responsavelLocalizado = responsavelDaLista;
				break;
			}
		}
		
		return responsavelLocalizado;
		
	}
	
	private boolean isExisteResponsavelNaListaComEsteCpf(String cpf){
		
		boolean existe = false;
		
		Iterator<Responsavel> itr = getResponsaveisAluno().iterator();
		while(itr.hasNext()){
			Responsavel responsavelDaLista = itr.next();
			if(responsavelDaLista.getId().getPessoa().getCpf().equals(cpf)){
				existe = true;
				break;
			}
		}
		
		return existe;
		
	}

	
	public Responsavel obterPaiAluno(){
		
		return localizarPrimeiroResponsavelAlunoPeloTipoResponsabilidade(TipoResponsabilidade.PAI);
		
	}
	
	public Responsavel obterMaeAluno(){
		
		return localizarPrimeiroResponsavelAlunoPeloTipoResponsabilidade(TipoResponsabilidade.MAE);
		
	}
	
	private Responsavel localizarPrimeiroResponsavelAlunoPeloTipoResponsabilidade(TipoResponsabilidade tipoResponsabilidadeProcurada){
		
		Responsavel responsavelProcurado = null;
		
		for(Responsavel responsavel : getResponsaveisAluno()){
			if(responsavel.getTipoResponsabeilidade() == tipoResponsabilidadeProcurada){
				responsavelProcurado = responsavel;
				break;
			}
		}
		
		return responsavelProcurado;
	}
	
	public Integer getId() {
		return id;
	}

	public Matricula getMatricula() {
		return matricula;
	}

	public Pessoa getPessoa() {
		return Pessoa;
	}


	public boolean isPaisSeparados() {
		return paisSeparados;
	}

	public SaudeAluno getSaudeAluno() {
		return saudeAluno;
	}

	public OndeAguardarAoTerminoAula getOndeAguardarAoTerminoAula() {
		return ondeAguardarAoTerminoAula;
	}

	public String getObs() {
		return obs;
	}

	public Turma getTurma() {
		return turma;
	}

	public List<Responsavel> getResponsaveisAluno() {
		return responsaveisAluno;
	}

	public Auditoria getAuditoria() {
		return auditoria;
	}

	public void setMatricula(Matricula matricula) {
		matricula.setAluno(this);
		this.matricula = matricula;
	}

	public void setPessoa(Pessoa pessoa) {
		Pessoa = pessoa;
	}


	public void setPaisSeparados(boolean paisSeparados) {
		this.paisSeparados = paisSeparados;
	}

	public void setSaudeAluno(SaudeAluno saudeAluno) {
		saudeAluno.setAluno(this);
		this.saudeAluno = saudeAluno;
	}

	public void setOndeAguardarAoTerminoAula(
			OndeAguardarAoTerminoAula ondeAguardarAoTerminoAula) {
		this.ondeAguardarAoTerminoAula = ondeAguardarAoTerminoAula;
	}

	public void setObs(String obs) {
		this.obs = obs;
	}

	public void setTurma(Turma turma) {
		this.turma = turma;
	}

	
	public void setResponsaveisAluno(List<Responsavel> responsaveisAluno) {
		this.responsaveisAluno = responsaveisAluno;
	}

	public void setAuditoria(Auditoria auditoria) {
		this.auditoria = auditoria;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Aluno other = (Aluno) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}

	
}
